package deployr.core;

import static deployr.core.Files.*;
import static deployr.core.Streams.*;

import java.io.*;
import java.util.*;
import java.util.zip.*;

public class Copy extends CopyOrZip {

	private Iterable<String> files = new LinkedList<String>();

	private final String root;

	private ZipListener zipListener;
	
	private Checksum checksum = new Checksum();
	
	public Copy(String root, Iterable<String> files) {
		this.root = root;
		this.files = files;
	}
	
	public Copy(String root, Checksum checksum) {
		this.root = root;
		this.checksum = checksum;
	}

	private boolean thereArentFiles() {
		return checksum.isEmpty() && !files.iterator().hasNext();
	}

	private boolean needContinue(Iterator<String> scanning) {
		return scanning.hasNext();
	}

	public String filename(String fullPath) {
		int sep = fullPath.lastIndexOf(File.separator);
		return fullPath.substring(sep + 1);
	}

	public void copy(String target) {

		if (thereArentFiles()) return;

		beforeCopy(target);
		copy(target, files.iterator());
		copy(target, checksum.iterator());
		afterCopy();
	}

	private void afterCopy() {
	}

	private void beforeCopy(String target) {
	}

	private void copy(String target, Iterator<String> copyingFiles) {
		while (needContinue(copyingFiles)) {
			copyTo(target, copyingFiles.next());
		}
	}

	private void copyTo(String target, String copyingFile) {
		if (isDirectory(copyingFile, root))
			return;
		File inputFile = copyByPathOrHash(root, copyingFile);
		File outputFile = makeOutputFile(target, copyingFile);
		doCopy(target, inputFile, outputFile);
		onCopying(outputFile);
	}

	private void doCopy(String target, File inputFile, File outputFile) {
		Streams.copy(inputStream(inputFile), outputStream(outputFile));
	}

	private File makeOutputFile(String target, String copyingFile) {
		File outputFile = new File(target, copyingFile);
		outputFile.getParentFile().mkdirs();
		return outputFile;
	}

	private File copyByPathOrHash(String root, String copyingFile) {
		File fileByPath = new File(root, copyingFile);
		if(fileByPath.exists()) return fileByPath;
		return new File(root, checksum.hash(copyingFile));
	}

	private void onCopying(File outputFile) {
		if(null != zipListener) zipListener.addZip(outputFile.getAbsolutePath());
	}

	public void attach(ZipListener zipListener) {
		this.zipListener = zipListener;
	}
}